﻿using System.CodeDom.Compiler;
namespace ShadowCode.Injection.Injections;

public class FactoryUnit(TransformData data, SyntaxNode node) : InjectionUnitBase(data)
{
    private readonly TransformData data = data;

    protected override INamedTypeSymbol CreateTypeDeclaration() =>
        throw new NotImplementedException("不应发生调用");

    protected override string CreateGroupKey() =>
        throw new NotImplementedException("不应发生调用");

    internal override bool CanSimple => false;

    #region GetMethod
    private IMethodSymbol GetMethod(INamedTypeSymbol type)
    {
        var method = GetMethod(node, type);
        if (!method.IsStatic)
        {
            var msg = $"'{method.Name}'必须为静态方法";
            throw Error.RequiredStatic.CreateError(msg, node);
        }
        return method;
    }

    private IMethodSymbol GetMethod(SyntaxNode node, INamedTypeSymbol type) => node switch
    {
        InvocationExpressionSyntax ies => GetMethod(data, ies),
        LiteralExpressionSyntax literal => GetMethod(data, literal, type),
        _ => throw Error.CreateUnexpected()
    };

    private IMethodSymbol GetMethod(TransformData data, LiteralExpressionSyntax node, INamedTypeSymbol type)
    {
        var name = data.GetConstantStringValue(node);
        if (name is not { Length: > 0 }) throw Error.CreateUnexpected(node);

        var method = type.GetMembers().OfType<IMethodSymbol>().FirstOrDefault(x => x.Name == name);
        if (method != null) return method;

        var msg = $"找不到名为'{name}'的静态方法";
        throw Error.NotFoundMethodName.CreateError(msg, node);
    }

    private IMethodSymbol GetMethod(TransformData data, InvocationExpressionSyntax node)
    {
        var exp = node.Expression;
        var target = node.ArgumentList.Arguments.FirstOrDefault();

        if (target is null || !(exp is IdentifierNameSyntax name &&
            name.Identifier.Text is "nameof"))
            throw Error.CreateUnexpected(node);

        var expNode = target.Expression;
        var method = data.GetSymbolInfo(expNode);

        if (method is not IMethodSymbol factory)
            throw Error.NotFoundMethodName.CreateError($"找不到名为'{name}'的静态方法", node);

        return factory;
    }
    #endregion

    #region CheckMethod
    private readonly static string serviceProvider = typeof(IServiceProvider).FullName;


    private void CheckKeyedSignature(IMethodSymbol method)
    {
        if (FindSignature(method, serviceProvider, "object")) return;
        var msg = $"'{method}'方法签名不正确!";
        throw Error.KeydSignatureError.CreateError(msg, node);
    }

    private void StandardSignature(IMethodSymbol method)
    {
        if (FindSignature(method, serviceProvider)) return;
        var msg = $"'{method}'方法签名不正确!";
        throw Error.StandardSignatureError.CreateError(msg, node);
    }

    /// <summary>
    /// 返回查找到的工厂方法
    /// </summary>
    private bool FindSignature(IMethodSymbol method, params string[] targets)
    {
        var target = targets.JoinString();
        return method.ContainingType.GetMembers()
              .OfType<IMethodSymbol>()
              .Where(x => x.Name == method.Name)
              .Any(x => GetParamType(x) == target);
    }

    private string GetParamType(IMethodSymbol method) => method
        .Parameters.Select(x => x.Type.UnNull().ToString()).JoinString();
    #endregion

    internal override void ImplementBuild(InjectionAttribute attribute,
        IndentedTextWriter writer, List<string> arguments)
    {
        throw new NotImplementedException("不应发生调用");
    }

    public string GetMethodPath(InjectionAttribute injection)
    {
        var method = GetMethod(injection.Target.Declaration);
        Check(injection, method);
        var methodType = method.ContainingType;
        var serviceType = injection.GetServiceType();
        return GetMethodPath(method, methodType, serviceType);
    }

    private string GetMethodPath(IMethodSymbol method, INamedTypeSymbol methodType, INamedTypeSymbol serviceType)
    {
        if (!methodType.IsGenericType
            || !methodType.OriginalDefinition.EqualsDefault(serviceType.OriginalDefinition))
            return GetMethodPath(method);

        // 补充泛型参数前检查泛型实参
        Error.CheckInstanceType(serviceType, data.Compilation, node);

        // 补充泛型参数       
        var newType = methodType.OriginalDefinition.Construct([.. serviceType.TypeArguments]);
        var res = newType.GetMembers().OfType<IMethodSymbol>()
            .First(x => x.OriginalDefinition.EqualsDefault(method.OriginalDefinition));

        return GetMethodPath(res);
    }

    private string GetMethodPath(IMethodSymbol method) =>
        method.ToDisplayString().Split('(')[0];

    private void Check(InjectionAttribute injection, IMethodSymbol method)
    {
        if (injection.Target is ConstructorUnit)
        {
            var error = "构造函数上不能使用factory！";
            throw Error.ProhibitFactory.CreateError(error, node);
        }

        if (injection.IsKeyed) CheckKeyedSignature(method);
        else StandardSignature(method);
    }
}